package com.drestuart.autofit;

import java.util.*;
import java.util.regex.*;
import java.util.Set;

/**
 * \class Template
 * 
 * \brief A small template engine class.  
 * 
 * This code was copied wholesale by me, Dan Stuart, from O'Reilly's Learning Java, 3rd edition, by Patrick Niemeyer and Jonathan Knudsen, pp 339-340. Most of this work is theirs.
 */

/**
 * @author Patrick Niemeyer, Jonathan Knudsen
 */
public class Template {

	private Properties values = new Properties(); ///< The key/value pairs
												  ///< we'll be replacing.

	/**
	 * The regex for capturing the template strings. They are of the form
	 * <--TEMPLATE:(property name) [comments]-->. The comments are optional, but
	 * the property name is not.
	 */
	private Pattern templateComment = Pattern
			.compile("(?si)<!--\\s*TEMPLATE:(\\w+).*?-->");

	private String text; ///< The text to apply the template to.

	public Template() {
	} ///< Default constructor. @see Template(String textIn).

	/**
	 * @author dstu
	 * 
	 *         \brief This constructor takes the target text as an argument.
	 */
	public Template(String textIn) {
		this.text = textIn;
	}

	/**
	 * \brief Set the target text.
	 */
	public void setText(String text) {
		this.text = text;
	}

	/**
	 * @param name
	 *            , value
	 * 
	 *            \brief Set the property name to value.
	 */
	public void set(String name, Object value) {
		values.setProperty(name, value.toString());
	}

	/**
	 * @author dstu
	 * 
	 *         \brief Delete all properties and values from values.
	 */
	public void clear() {
		values = new Properties();
	}

	/**
	 * \brief Fill in the template text with the values supplied.
	 * 
	 * @see fillIn(String text)
	 */
	public String fillIn() {
		return fillIn(this.text);
	}

	/**
	 * @author dstu
	 * 
	 * @see allPropertiesAssigned(String text)
	 * @see fillIn(boolean check, String textIn)
	 * @see fillIn(String text)
	 */
	public String fillIn(boolean check) throws BlankPropertiesException {
		return fillIn(check, this.text);
	}

	/**
	 * @author dstu
	 * 
	 *         \brief Fill in the provided template textIn with the values
	 *         supplied, checking that all property names in the template have
	 *         been supplied. If not, throws a BlankPropertiesException.
	 * 
	 * @see fillIn(String text)
	 * @see allPropertiesAssigned(String text)
	 */
	public String fillIn(boolean check, String textIn)
			throws BlankPropertiesException {
		if (check && this.allPropertiesAssigned(textIn)) {
			return fillIn(textIn);
		} else {
			throw new BlankPropertiesException();
		}
	}

	/**
	 * @author dstu
	 * 
	 *         \brief Fill in the provided template textIn with the values
	 *         supplied.
	 */
	public String fillIn(String text) {
		Matcher matcher = templateComment.matcher(text);

		StringBuffer buffer = new StringBuffer();

		while (matcher.find()) {
			String name = matcher.group(1);
			String value = values.getProperty(name);

			if (value == null) {
				value = "";
			}

			matcher.appendReplacement(buffer, value);
		}

		matcher.appendTail(buffer);
		return buffer.toString();
	}

	/**
	 * @author dstu
	 * 
	 * @see allPropertiesAssigned(String text)
	 */
	public boolean allPropertiesAssigned() {
		return allPropertiesAssigned(text);
	}

	/**
	 * @author dstu
	 * 
	 *         \brief Checks that all property names in the template have been
	 *         supplied to the \ref values member.
	 */
	public boolean allPropertiesAssigned(String text) {
		Matcher matcher = templateComment.matcher(text);
		Set<Object> vals = values.keySet();

		while (matcher.find()) {
			String name = matcher.group(1);

			if (!(vals.contains(name))) {
				return false;
			}
		}
		return true;
	}

}
